/**
@author		Jong Min, Lee
@date		  10/01/2014
@breif		Dicom study class 

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#pragma once

#include <vector>

#include "Taurus_Util/Macros.h"
#include "Taurus_DcmData/Defines.h"

//forward declarations
class CDcmSeries;
class IStudyInfo;

/**
@brief		study media
*/
enum DcmStudyMedia
{
  DcmStudyMediaFirstInvalid = -1,
  DcmStudyMediaServer,
  DcmStudyMediaLocalDisk,
  DcmStudyMediaDICOMDIR,
  DcmStudyMediaLastInvalid
};

/**
@brief		dcm study class
*/
class TAURUS_DCMDATA_EXPORT CDcmStudy
{
private:
  /**
  @brief		default constructor
  */
  CDcmStudy();

  DISALLOW_COPY_AND_ASSIGN(CDcmStudy);

public:
  friend class CDcmStudyProducer;

  /**
  @brief		destructor
  */
  ~CDcmStudy();

  /**
  @brief		get how many objects reference to dcm study
  @return		reference count
  */
  inline int getRefCount() const
  {
    return m_theRefCount;
  }

  /**
  @brief		increase reference count by one
  */
  inline void increaseRefCount()
  {
    m_theRefCount++;
  }

  /**
  @brief		decrease reference count by one
  */
  inline void decreaseRefCount()
  {
    m_theRefCount--;
  }

  /**
  @brief		get where dcm study come from
  @return		study media
  */
  inline DcmStudyMedia getMedia() const
  {
    return m_theMedia;
  }

  /**
  @brief		get study key
  @return		null-terminated string represents study key
  */
  inline const TCHAR* getKey() const
  {
    return m_theKey;
  }

  /**
  @brief		find a dcm series by series key
  @param		key null-terminated represents series key
  @return		pointer to dcm series if found, nullptr if not
  */
  CDcmSeries* findSeries(const TCHAR* key) const;

  /**
  @brief		find an image dcm series by series key
  @param		key null-terminated string represents series key
  @return		pointer to dcm series if found, nullptr if not
  */
  CDcmSeries* findImageSeries(const TCHAR* key) const;

  /**
  @brief		find a none image dcm series by series key
  @param		key null-terminated string represents series key
  @return		pointer to dcm series if found, nullptr if not
  */
  CDcmSeries* findNoneImageSeries(const TCHAR* key) const;

  /**
  @brief		add a dcm series to dcm study
  @param		series pointer to dcm series to be added
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD addSeries(CDcmSeries* series);

  /**
  @brief		get the number of dcm series belong to dcm study
  @return		the number of dcm series belong to dcm study
  */
  unsigned getNumSeries() const;

  /**
  @brief		get the number of image dcm series belong to dcm study
  @return		the number of image dcm series belong to dcm study
  */
  unsigned getNumImageSeries() const;

  /**
  @brief		access an image dcm series
  @param		index the index number of an image dcm series to be accessed
  @return		pointer to dcm series if found, nullptr if not
  */
  CDcmSeries* getImageSeries(const unsigned int index) const;

  /**
  @brief		get the number of none image dcm series belong to dcm study
  @return		the number of none dcm series belong to dcm study
  */
  unsigned getNumNoneImageSeries() const;

  /**
  @brief		access a none image dcm series
  @param		index the index number of none image dcm series to be accessed
  @return		pointer to dcm series if found, nullptr if not
  */
  CDcmSeries* getNoneImageSeries(const unsigned int index) const;

  /**
  @brief		remove not referenced dcm series
  */
  DWORD removeNoRefSeries();

private:
  /**
  @brief		initialize dcm study
  */
  void init();

  /**
  @brief		destroy dcm study. this method should be only used in destructor
  */
  void destroy();

  /**
  @brief		remove all dcm series
  */
  void removeAllSeries();

  /**
  @brief		remove all image dcm series
  */
  void removeAllImageSeries();

  /**
  @brief		remove all none image dcm series
  */
  void removeAllNoneImageSeries();

  /**
  @brief		remove not referenced elements in dcm series
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  DWORD removeNotRefElemSeries(std::vector<CDcmSeries*>& series);

private:

  //reference count
  int m_theRefCount;

  //media
  DcmStudyMedia m_theMedia;

  //study key
  CString m_theKey;

  //image series
  std::vector<CDcmSeries*> m_theImageSeries;

  //none image series
  std::vector<CDcmSeries*> m_theNoneImageSeries;
};

/**
@brief		dcm study producer class
*/
class TAURUS_DCMDATA_EXPORT CDcmStudyProducer
{
public:
  /**
  @brief		create a new dcm study by using study information
  @param		studyInfo study information
  @param    media study media
  @param    outStudy variable in which pointer to new dcm study is stored
  @return		ERROR_SUCCESS if succeeds, an error code otherwise
  */
  static DWORD produce(IStudyInfo& studyInfo,
                       DcmStudyMedia media,
                       CDcmStudy*& outStudy);
};